package com.techsun.presto.decode.utils;

import com.google.common.primitives.Bytes;
import org.apache.logging.log4j.util.Strings;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.codehaus.plexus.util.StringUtils;


import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.Base64;


public class EncryptionHelper
{
    /**
     * 静态块内导入解密包
     */
    static {
        try {
            Security.addProvider(new BouncyCastleProvider());
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * des加密数据
     *
     * @param message 加密数据
     * @param key key
     * @return String
     */
    public static String encryptByDes(String message, String key)
            throws Exception
    {
        String strRetValue;
        String byteCode = "UTF-8";
        String des = "DES/ECB/NoPadding";
        Cipher cipher = Cipher.getInstance(des);
        key = processKey(key);
        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes(byteCode));
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] content = message.getBytes(byteCode);
        content = Bytes.ensureCapacity(content, 16, 0);
        byte[] retByte = cipher.doFinal(content);
        strRetValue = bytesToHex(retByte);
        return strRetValue.toUpperCase();
    }

    /**
     * des解密数据
     *
     * @param message 加密数据
     * @param key key
     * @return String
     */
    public static String decryptByDes(String message, String key)
            throws Exception
    {
        String byteCode = "UTF-8";
        String des = "DES/ECB/NoPadding";
        byte[] retByte;
        byte[] bytesrc = convertHexString(message);
        Cipher cipher = Cipher.getInstance(des);
        key = processKey(key);
        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes(byteCode));
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        retByte = cipher.doFinal(bytesrc);
        return Strings.trimToNull(new String(retByte));
    }

    /**
     * 将byte[]转换为16进制字符串
     *
     * @param bytes 转换的数组
     * @return String
     */
    private static String bytesToHex(byte[] bytes)
    {
        StringBuilder buf = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            buf.append(String.format("%02x", b & 0xff));
        }
        return buf.toString();
    }

    /**
     * 将String转换为byte[]
     *
     * @param message 需转换的字符串
     * @return byte[]
     */
    private static byte[] convertHexString(String message)
    {
        byte[] digest = new byte[message.length() / 2];
        for (int i = 0; i < digest.length; i++) {
            String byteString = message.substring(2 * i, 2 * i + 2);
            int byteValue = Integer.parseInt(byteString, 16);
            digest[i] = (byte) byteValue;
        }
        return digest;
    }

    /**
     * 将String添加横线
     *
     * @param raw 需要添加的数据
     * @return byte[]
     */
    public static String stringToUuid(String raw)
    {
        int rawLength = 20;
        StringBuilder sb = new StringBuilder();
        String mark = "-";
        if (raw.length() > rawLength) {
            String subOne = raw.substring(0, 8);
            String subTwo = raw.substring(8, 12);
            String subThree = raw.substring(12, 16);
            String subFour = raw.substring(16, 20);
            String subFive = raw.substring(20);
            sb.append(subOne);
            sb.append(mark);
            sb.append(subTwo);
            sb.append(mark);
            sb.append(subThree);
            sb.append(mark);
            sb.append(subFour);
            sb.append(mark);
            sb.append(subFive);
        }
        return sb.toString();
    }

    /**
     * 获得一个去掉"-"符号的UUID
     *
     * @return String
     */
    public static String uuidToString(String raw)
    {
        return raw.replace("-", "");
    }

    private static String processKey(String key)
    {
        int keyLength = 8;
        if (StringUtils.isNotEmpty(key) && key.length() < keyLength) {
            key += "00000000";
        }
        key = key.substring(0, 8);
        return key;
    }

    /**
     * des加密,不足8的偶数自动填补
     *
     * @param message 加密数据
     * @param key key
     * @return String
     */
    public static String encryptByDesPkcs5Padding(String message, String key)
            throws Exception
    {
        String strRetValue;
        String byteCode = "UTF-8";
        String des = "DES/ECB/PKCS5Padding";
        Cipher cipher = Cipher.getInstance(des);
        key = processKey(key);
        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes(byteCode));
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] content = message.getBytes(byteCode);
        int minLength;
        if (message.length() % 8 == 0) {
            minLength = (message.length());
        }
        else {
            minLength = (message.length() + 8) / 8 * 8;
        }
        content = Bytes.ensureCapacity(content, minLength, 0);
        byte[] retByte = cipher.doFinal(content);
        strRetValue = bytesToHex(retByte);
        return strRetValue.toUpperCase();
    }

    /**
     * des解密数据
     *
     * @param message 解密数据
     * @param key key
     * @return String
     */
    public static String decryptByDesPkcs5Padding(String message, String key)
            throws Exception
    {
        String byteCode = "UTF-8";
        String des = "DES/ECB/PKCS5Padding";
        byte[] retByte;
        byte[] bytesrc = convertHexString(message);
        Cipher cipher = Cipher.getInstance(des);
        key = processKey(key);
        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes(byteCode));
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        retByte = cipher.doFinal(bytesrc);
        return Strings.trimToNull(new String(retByte));
    }

    /**
     * @param data 明文
     * @param key 密钥，长度16
     * @param iv 偏移量，长度16
     * @return 密文
     */
    public static String encryptAes(String data, String key, String iv)
            throws Exception
    {
        Security.addProvider(new BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");

        byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
        //针对AES/CBC/NoPadding情况适用
        // int blockSize = cipher.getBlockSize();
        // int plaintextLength = dataBytes.length;
        //
        // if (plaintextLength % blockSize != 0) {
        //     plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
        // }
        //
        // byte[] plaintext = new byte[plaintextLength];
        // System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);

        SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
        IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));

        cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
        byte[] encrypted = cipher.doFinal(dataBytes);

        String mixStr = Base64.getMimeEncoder().encodeToString(encrypted).trim();
        mixStr = mixStr.replaceAll("/", "_").replaceAll("\\+", "-");
        return mixStr;
    }

    /**
     * @param data 密文
     * @param key 密钥，长度16
     * @param iv 偏移量，长度16
     * @return 明文
     */
    public static String decryptAes(String data, String key, String iv)
            throws Exception
    {
        data = data.replaceAll("_", "/").replaceAll("-", "\\+");
        Security.addProvider(new BouncyCastleProvider());
        byte[] encrypted1 = Base64.getMimeDecoder().decode(data.getBytes(StandardCharsets.UTF_8));

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
        IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));

        cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

        byte[] original = cipher.doFinal(encrypted1);
        String originalString = new String(original, StandardCharsets.UTF_8);
        return originalString.trim();
    }

    public static byte[] base642byte(String data)
    {
        return org.apache.commons.codec.binary.Base64.decodeBase64(data);
    }
}
